package com.nulldev.util.data.FastMath.impls;

/*
 * Copyright 2012-2015 Jeff Hain
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
@SuppressWarnings("unused")
class NumbersUtils {
	// --------------------------------------------------------------------------
	// MEMBERS
	// --------------------------------------------------------------------------

	/**
	 * Double.MIN_NORMAL since Java 6.
	 */
	public static final double DOUBLE_MIN_NORMAL = Double.longBitsToDouble(0x0010000000000000L); // 2.2250738585072014E-308

	/**
	 * Float.MIN_NORMAL since Java 6.
	 */
	public static final float FLOAT_MIN_NORMAL = Float.intBitsToFloat(0x00800000); // 1.17549435E-38f

	private static final int MIN_DOUBLE_EXPONENT = -1074;
	private static final int MAX_DOUBLE_EXPONENT = 1023;

	/**
	 * All possible upper case chars for representing a number as a String.
	 */
	private final static char[] CHAR_BY_DIGIT;
	static {
		final char minDecimal = '0';
		final char maxDecimal = '9';
		final int n1 = maxDecimal - minDecimal + 1;
		final char minLetter = 'A';
		final char maxLetter = 'Z';
		final int n2 = maxLetter - minLetter + 1;
		CHAR_BY_DIGIT = new char[n1 + n2];
		int i = 0;
		for (char c = minDecimal; c <= maxDecimal; c++) {
			CHAR_BY_DIGIT[i++] = c;
		}
		for (char c = minLetter; c <= maxLetter; c++) {
			CHAR_BY_DIGIT[i++] = c;
		}
	}

	/**
	 * For power-of-two radixes only.
	 */
	private static final int[] DIV_SHIFT_BY_RADIX;
	static {
		DIV_SHIFT_BY_RADIX = new int[32 + 1];
		int shift = 1;
		for (int radix = 2; radix <= 32; radix *= 2) {
			DIV_SHIFT_BY_RADIX[radix] = shift++;
		}
	}

	private final static int[] MAX_NBR_OF_NEG_INT_DIGITS_BY_RADIX = new int[Character.MAX_RADIX + 1];
	private final static int[] MAX_NBR_OF_NEG_LONG_DIGITS_BY_RADIX = new int[Character.MAX_RADIX + 1];
	static {
		for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) {
			/*
			 * Brutal but works. -1 for the sign.
			 */
			MAX_NBR_OF_NEG_INT_DIGITS_BY_RADIX[radix] = Integer.toString(Integer.MIN_VALUE, radix).length() - 1;
			MAX_NBR_OF_NEG_LONG_DIGITS_BY_RADIX[radix] = Long.toString(Long.MIN_VALUE, radix).length() - 1;
		}
	}

	static final double NO_CSN_MIN_BOUND_INCL = 1e-3;
	static final double NO_CSN_MAX_BOUND_EXCL = 1e7;

	private static final double PIO2_HI = Double.longBitsToDouble(0x3FF921FB54400000L); // 1.57079632673412561417e+00 first 33 bits of pi/2
	private static final double PIO2_LO = Double.longBitsToDouble(0x3DD0B4611A626331L); // 6.07710050650619224932e-11 pi/2 - PIO2_HI
	private static final double PI_HI = 2 * PIO2_HI;
	private static final double PI_LO = 2 * PIO2_LO;
	private static final double TWOPI_HI = 4 * PIO2_HI;
	private static final double TWOPI_LO = 4 * PIO2_LO;

	// --------------------------------------------------------------------------
	// PUBLIC METHODS
	// --------------------------------------------------------------------------

	/**
	 * @return True if the specified values are equal or both NaN, false otherwise.
	 */
	public static boolean equal(float a, float b) {
		// Only does one test if a == b.
		return (a == b) ? true : ((a != a) && (b != b));
	}

	/**
	 * @return True if the specified values are equal or both NaN, false otherwise.
	 */
	public static boolean equal(double a, double b) {
		// Only does one test if a == b.
		return (a == b) ? true : ((a != a) && (b != b));
	}

	/**
	 * @return True if the specified value is a mathematical integer, false
	 *         otherwise (which includes NaN and +-Infinity).
	 */
	public static boolean isMathematicalInteger(float value) {
		// Doing magnitude test first, for cast
		// might be very slow for huge values.
		// It also helps be faster for huge values,
		// for which the test with cast always fail.
		value = Math.abs(value);
		return ((value >= (float) (1 << 23) && (value != Float.POSITIVE_INFINITY))) || (value == (float) (int) value);
	}

	/**
	 * @return True if the specified value is a mathematical integer, false
	 *         otherwise (which includes NaN and +-Infinity).
	 */
	public static boolean isMathematicalInteger(double value) {
		// Doing magnitude test first, for cast
		// might be very slow for huge values.
		// It also helps be faster for huge values,
		// for which the test with cast always fail.
		value = Math.abs(value);
		return ((value >= (double) (1L << 52)) && (value != Double.POSITIVE_INFINITY)) || (value == (double) (long) value);
	}

	/**
	 * @param value A float value.
	 * @return True if the specified value is equidistant from two adjacent
	 *         mathematical integers, false otherwise (which includes NaN and
	 *         +-Infinity).
	 */
	public static boolean isEquidistant(float value) {
		if (false) {
			// Also works, but slower.
			final int bits = Float.floatToRawIntBits(value);
			final int exponent = ((bits >> 23) & 0xFF) - 127;
			final int nbrOfPostCommaBits = 23 - exponent;
			if ((nbrOfPostCommaBits <= 0) || (nbrOfPostCommaBits >= 25)) {
				// No mantissa bit after comma, or all mantissa bits
				// (including implicit 1) are at least one bit away from it.
				// System.out.println("can't be");
				return false;
			}
			final int mantissa = 0x00800000 | (bits & 0x007FFFFF);
			final int postCommaMask = ~((-1) << nbrOfPostCommaBits);
			// True if in post-comma bits the only 1-bit is the one for 0.5.
			return ((mantissa & postCommaMask) == (1 << (nbrOfPostCommaBits - 1)));
		}
		final float valueAbs = Math.abs(value);
		if (!(valueAbs < (float) (1 << 23))) {
			// NaN or too large to have a chance
			return false;
		}
		final float twice = valueAbs + valueAbs;
		// Test on twice first, for it's the most likely to fail.
		return (twice == (float) (int) twice) && (value != (float) (int) value);
	}

	/**
	 * @param value A double value.
	 * @return True if the specified value is equidistant from two adjacent
	 *         mathematical integers, false otherwise (which includes NaN and
	 *         +-Infinity).
	 */
	public static boolean isEquidistant(double value) {
		if (false) {
			// Also works, but slower.
			final long bits = Double.doubleToRawLongBits(value);
			final int exponent = (((int) (bits >> 52)) & 0x7FF) - 1023;
			final int nbrOfPostCommaBits = 52 - exponent;
			if ((nbrOfPostCommaBits <= 0) || (nbrOfPostCommaBits >= 54)) {
				// No mantissa bit after comma, or all mantissa bits
				// (including implicit 1) are at least one bit away from it.
				return false;
			}
			final long mantissa = 0x0010000000000000L | (bits & 0x000FFFFFFFFFFFFFL);
			final long postCommaMask = ~((-1L) << nbrOfPostCommaBits);
			// True if in post-comma bits the only 1-bit is the one for 0.5.
			return ((mantissa & postCommaMask) == (1L << (nbrOfPostCommaBits - 1)));
		}
		final double valueAbs = Math.abs(value);
		if (!(valueAbs < (double) (1L << 52))) {
			return false;
		}
		final double twice = valueAbs + valueAbs;
		// Test on twice first, for it's the most likely to fail.
		return (twice == (double) (long) twice) && (value != (double) (long) value);
	}

	/**
	 * @param hints A float value.
	 * @return True if the specified value is NaN or +-Infinity, false otherwise.
	 */
	public static boolean isNaNOrInfinite(float a) {
		// a-a is not equal to 0.0f (and is NaN) <-> a is NaN or +-Infinity
		return !(a - a == 0.0f);
	}

	/**
	 * @param hints A double value.
	 * @return True if the specified value is NaN or +-Infinity, false otherwise.
	 */
	public static boolean isNaNOrInfinite(double a) {
		// a-a is not equal to 0.0 (and is NaN) <-> a is NaN or +-Infinity
		return !(a - a == 0.0);
	}

	/**
	 * @param value A float value.
	 * @return -1 if sign bit is 1, 1 if sign bit is 0.
	 */
	public static int signFromBit(float value) {
		return ((Float.floatToRawIntBits(value) >> 30) | 1);
	}

	/**
	 * @param value A double value.
	 * @return -1 if sign bit is 1, 1 if sign bit is 0.
	 */
	public static long signFromBit(double value) {
		// Returning a long, to avoid useless cast into int.
		return ((Double.doubleToRawLongBits(value) >> 62) | 1);
	}

	/*
	 * min/max ranges
	 */

	/**
	 * @return True if the specified value is in the specified range (inclusive),
	 *         false otherwise.
	 */
	public static boolean isInRange(int min, int max, int a) {
		return (min <= a) && (a <= max);
	}

	/**
	 * @return True if the specified value is in the specified range (inclusive),
	 *         false otherwise.
	 */
	public static boolean isInRange(long min, long max, long a) {
		return (min <= a) && (a <= max);
	}

	/**
	 * Returns false if any value is NaN.
	 * 
	 * @return True if the specified value is in the specified range (inclusive),
	 *         false otherwise.
	 */
	public static boolean isInRange(float min, float max, float a) {
		return (min <= a) && (a <= max);
	}

	/**
	 * Returns false if any value is NaN.
	 * 
	 * @return True if the specified value is in the specified range (inclusive),
	 *         false otherwise.
	 */
	public static boolean isInRange(double min, double max, double a) {
		return (min <= a) && (a <= max);
	}

	/*
	 * 
	 */

	/**
	 * @return True if does not throw.
	 * @throws IllegalArgumentException if the specified value is not in the
	 *                                  specified range (inclusive).
	 */
	public static boolean checkIsInRange(int min, int max, int a) {
		if (!isInRange(min, max, a)) {
			throw new IllegalArgumentException(a + " not in [" + min + "," + max + "]");
		}
		return true;
	}

	/**
	 * @return True if does not throw.
	 * @throws IllegalArgumentException if the specified value is not in the
	 *                                  specified range (inclusive).
	 */
	public static boolean checkIsInRange(long min, long max, long a) {
		if (!isInRange(min, max, a)) {
			throw new IllegalArgumentException(a + " not in [" + min + "," + max + "]");
		}
		return true;
	}

	/**
	 * @return True if does not throw.
	 * @throws IllegalArgumentException if the specified value is not in the
	 *                                  specified range (inclusive) or any parameter
	 *                                  is NaN.
	 */
	public static boolean checkIsInRange(float min, float max, float a) {
		if (!isInRange(min, max, a)) {
			throw new IllegalArgumentException(a + " not in [" + min + "," + max + "]");
		}
		return true;
	}

	/**
	 * @return True if does not throw.
	 * @throws IllegalArgumentException if the specified value is not in the
	 *                                  specified range (inclusive) or any parameter
	 *                                  is NaN.
	 */
	public static boolean checkIsInRange(double min, double max, double a) {
		if (!isInRange(min, max, a)) {
			throw new IllegalArgumentException(a + " not in [" + min + "," + max + "]");
		}
		return true;
	}

	/*
	 * 
	 */

	/**
	 * @param min A value.
	 * @param max A value.
	 * @param a   A value.
	 * @return min if a <= min, else max if a >= max, else a.
	 */
	public static int toRange(int min, int max, int a) {
		if (a <= min) {
			return min;
		} else if (a >= max) {
			return max;
		} else {
			return a;
		}
	}

	/**
	 * @param min A value.
	 * @param max A value.
	 * @param a   A value.
	 * @return min if a <= min, else max if a >= max, else a.
	 */
	public static long toRange(long min, long max, long a) {
		if (a <= min) {
			return min;
		} else if (a >= max) {
			return max;
		} else {
			return a;
		}
	}

	/**
	 * @param min A value.
	 * @param max A value.
	 * @param a   A value.
	 * @return min if a <= min, else max if a >= max, else a.
	 */
	public static float toRange(float min, float max, float a) {
		if (a <= min) {
			return min;
		} else if (a >= max) {
			return max;
		} else {
			return a;
		}
	}

	/**
	 * @param min A value.
	 * @param max A value.
	 * @param a   A value.
	 * @return min if a <= min, else max if a >= max, else a.
	 */
	public static double toRange(double min, double max, double a) {
		if (a <= min) {
			return min;
		} else if (a >= max) {
			return max;
		} else {
			return a;
		}
	}

	/*
	 * bitwise ranges
	 */

	/**
	 * @param bitSize A number of bits, in [1,32].
	 * @return True if the specified value fits as a signed integer over the
	 *         specified number of bits, false otherwise.
	 * @throws IllegalArgumentException if the specified number of bits is not in
	 *                                  [1,32].
	 */
	public static boolean isInRangeSigned(int a, int bitSize) {
		checkBitSizeForSignedInt(bitSize);
		return (minSignedIntForBitSize_noCheck(bitSize) <= a) && (a <= maxSignedIntForBitSize_noCheck(bitSize));
	}

	/**
	 * @param bitSize A number of bits, in [1,64].
	 * @return True if the specified value fits as a signed integer over the
	 *         specified number of bits, false otherwise.
	 * @throws IllegalArgumentException if the specified number of bits is not in
	 *                                  [1,64].
	 */
	public static boolean isInRangeSigned(long a, int bitSize) {
		checkBitSizeForSignedLong(bitSize);
		return (minSignedLongForBitSize_noCheck(bitSize) <= a) && (a <= maxSignedLongForBitSize_noCheck(bitSize));
	}

	/**
	 * @param bitSize A number of bits, in [1,31].
	 * @return True if the specified value fits as an unsigned integer over the
	 *         specified number of bits, false otherwise.
	 * @throws IllegalArgumentException if the specified number of bits is not in
	 *                                  [1,31].
	 */
	public static boolean isInRangeUnsigned(int a, int bitSize) {
		return isInRange(0, maxUnsignedIntForBitSize(bitSize), a);
	}

	/**
	 * @param bitSize A number of bits, in [1,63].
	 * @return True if the specified value fits as an unsigned integer over the
	 *         specified number of bits, false otherwise.
	 * @throws IllegalArgumentException if the specified number of bits is not in
	 *                                  [1,63].
	 */
	public static boolean isInRangeUnsigned(long a, int bitSize) {
		return isInRange(0, maxUnsignedLongForBitSize(bitSize), a);
	}

	/*
	 * 
	 */

	/**
	 * @param bitSize A number of bits, in [1,32].
	 * @return True if does not throw.
	 * @throws IllegalArgumentException if the specified value does not fit as a
	 *                                  signed integer over the specified number of
	 *                                  bits.
	 */
	public static boolean checkIsInRangeSigned(int a, int bitSize) {
		if (!isInRangeSigned(a, bitSize)) {
			throw new IllegalArgumentException(a + " does not fit as a signed value over " + bitSize + " bits");
		}
		return true;
	}

	/**
	 * @param bitSize A number of bits, in [1,64].
	 * @return True if does not throw.
	 * @throws IllegalArgumentException if the specified value does not fit as a
	 *                                  signed integer over the specified number of
	 *                                  bits.
	 */
	public static boolean checkIsInRangeSigned(long a, int bitSize) {
		if (!isInRangeSigned(a, bitSize)) {
			throw new IllegalArgumentException(a + " does not fit as a signed value over " + bitSize + " bits");
		}
		return true;
	}

	/**
	 * @param bitSize A number of bits, in [1,31].
	 * @return True if does not throw.
	 * @throws IllegalArgumentException if the specified value does not fit as an
	 *                                  unsigned integer over the specified number
	 *                                  of bits.
	 */
	public static boolean checkIsInRangeUnsigned(int a, int bitSize) {
		if (!isInRangeUnsigned(a, bitSize)) {
			throw new IllegalArgumentException(a + " does not fit as an unsigned value over " + bitSize + " bits");
		}
		return true;
	}

	/**
	 * @param bitSize A number of bits, in [1,63].
	 * @return True if does not throw.
	 * @throws IllegalArgumentException if the specified value does not fit as an
	 *                                  unsigned integer over the specified number
	 *                                  of bits.
	 */
	public static boolean checkIsInRangeUnsigned(long a, int bitSize) {
		if (!isInRangeUnsigned(a, bitSize)) {
			throw new IllegalArgumentException(a + " does not fit as an unsigned value over " + bitSize + " bits");
		}
		return true;
	}

	/*
	 * masks (int)
	 */

	/**
	 * @param bitSize A number of bits, in [0,32].
	 * @return Mask with the specified number of left bits set with 0, and other
	 *         bits set with 1.
	 */
	public static int intMaskMSBits0(int bitSize) {
		checkIsInRange(0, 32, bitSize);
		// Shifting in two times, for >>> doesn't work for full bit size (<< as well).
		final int halfish = (bitSize >> 1);
		return ((-1) >>> halfish) >>> (bitSize - halfish);
	}

	/**
	 * @param bitSize A number of bits, in [0,32].
	 * @return Mask with the specified number of left bits set with 1, and other
	 *         bits set with 0.
	 */
	public static int intMaskMSBits1(int bitSize) {
		return ~intMaskMSBits0(bitSize);
	}

	/**
	 * @param bitSize A number of bits, in [0,32].
	 * @return Mask with the specified number of right bits set with 0, and other
	 *         bits set with 1.
	 */
	public static int intMaskLSBits0(int bitSize) {
		return ~intMaskMSBits0(32 - bitSize);
	}

	/**
	 * @param bitSize A number of bits, in [0,32].
	 * @return Mask with the specified number of right bits set with 1, and other
	 *         bits set with 0.
	 */
	public static int intMaskLSBits1(int bitSize) {
		return intMaskMSBits0(32 - bitSize);
	}

	/*
	 * masks (long)
	 */

	/**
	 * @param bitSize A number of bits, in [0,64].
	 * @return Mask with the specified number of left bits set with 0, and other
	 *         bits set with 1.
	 */
	public static long longMaskMSBits0(int bitSize) {
		checkIsInRange(0, 64, bitSize);
		// Shifting in two times, for >>> doesn't work for full bit size (<< as well).
		final int halfish = (bitSize >> 1);
		return ((-1L) >>> halfish) >>> (bitSize - halfish);
	}

	/**
	 * @param bitSize A number of bits, in [0,64].
	 * @return Mask with the specified number of left bits set with 1, and other
	 *         bits set with 0.
	 */
	public static long longMaskMSBits1(int bitSize) {
		return ~longMaskMSBits0(bitSize);
	}

	/**
	 * @param bitSize A number of bits, in [0,64].
	 * @return Mask with the specified number of right bits set with 0, and other
	 *         bits set with 1.
	 */
	public static long longMaskLSBits0(int bitSize) {
		return ~longMaskMSBits0(64 - bitSize);
	}

	/**
	 * @param bitSize A number of bits, in [0,64].
	 * @return Mask with the specified number of right bits set with 1, and other
	 *         bits set with 0.
	 */
	public static long longMaskLSBits1(int bitSize) {
		return longMaskMSBits0(64 - bitSize);
	}

	/*
	 * signed/unsigned
	 */

	/**
	 * @return Unsigned value corresponding to bits of the specified byte.
	 */
	public static short byteAsUnsigned(byte value) {
		return (short) (((short) value) & 0xFF);
	}

	/**
	 * @return Unsigned value corresponding to bits of the specified short.
	 */
	public static int shortAsUnsigned(short value) {
		return ((int) value) & 0xFFFF;
	}

	/**
	 * @return Unsigned value corresponding to bits of the specified int.
	 */
	public static long intAsUnsigned(int value) {
		return ((long) value) & 0xFFFFFFFF;
	}

	/*
	 * bitwise ranges
	 */

	/**
	 * @return True if a signed int value can be read over the specified number of
	 *         bits, i.e. if it is in [1,32], false otherwise.
	 */
	public static boolean isValidBitSizeForSignedInt(int bitSize) {
		return (bitSize > 0) && (bitSize <= 32);
	}

	/**
	 * @return True if a signed long value can be read over the specified number of
	 *         bits, i.e. if it is in [1,64], false otherwise.
	 */
	public static boolean isValidBitSizeForSignedLong(int bitSize) {
		return (bitSize > 0) && (bitSize <= 64);
	}

	/**
	 * @return True if an unsigned int value can be read over the specified number
	 *         of bits, i.e. if it is in [1,31], false otherwise.
	 */
	public static boolean isValidBitSizeForUnsignedInt(int bitSize) {
		return (bitSize > 0) && (bitSize < 32);
	}

	/**
	 * @return True if an unsigned long value can be read over the specified number
	 *         of bits, i.e. if it is in [1,63], false otherwise.
	 */
	public static boolean isValidBitSizeForUnsignedLong(int bitSize) {
		return (bitSize > 0) && (bitSize < 64);
	}

	/*
	 * 
	 */

	/**
	 * @return True if does not throw.
	 * @throws IllegalArgumentException if a signed int value can't be read over the
	 *                                  specified number of bits, i.e. if it is not
	 *                                  in [1,32].
	 */
	public static boolean checkBitSizeForSignedInt(int bitSize) {
		if (!isValidBitSizeForSignedInt(bitSize)) {
			throw new IllegalArgumentException("bit size [" + bitSize + "] must be in [1,32] for signed int values");
		}
		return true;
	}

	/**
	 * @return True if does not throw.
	 * @throws IllegalArgumentException if a signed long value can't be read over
	 *                                  the specified number of bits, i.e. if it is
	 *                                  not in [1,64].
	 */
	public static boolean checkBitSizeForSignedLong(int bitSize) {
		if (!isValidBitSizeForSignedLong(bitSize)) {
			throw new IllegalArgumentException("bit size [" + bitSize + "] must be in [1,64] for signed long values");
		}
		return true;
	}

	/**
	 * @return True if does not throw.
	 * @throws IllegalArgumentException if an unsigned int value can't be read over
	 *                                  the specified number of bits, i.e. if it is
	 *                                  not in [1,31].
	 */
	public static boolean checkBitSizeForUnsignedInt(int bitSize) {
		if (!isValidBitSizeForUnsignedInt(bitSize)) {
			throw new IllegalArgumentException("bit size [" + bitSize + "] must be in [1,31] for unsigned int values");
		}
		return true;
	}

	/**
	 * @return True if does not throw.
	 * @throws IllegalArgumentException if an unsigned long value can't be read over
	 *                                  the specified number of bits, i.e. if it is
	 *                                  not in [1,63].
	 */
	public static boolean checkBitSizeForUnsignedLong(int bitSize) {
		if (!isValidBitSizeForUnsignedLong(bitSize)) {
			throw new IllegalArgumentException("bit size [" + bitSize + "] must be in [1,63] for unsigned long values");
		}
		return true;
	}

	/*
	 * 
	 */

	/**
	 * @param bitSize A number of bits in [1,32].
	 * @return The min signed int value that can be stored over the specified number
	 *         of bits.
	 * @throws IllegalArgumentException if the specified number of bits is out of
	 *                                  range.
	 */
	public static int minSignedIntForBitSize(int bitSize) {
		checkBitSizeForSignedInt(bitSize);
		return minSignedIntForBitSize_noCheck(bitSize);
	}

	/**
	 * @param bitSize A number of bits in [1,64].
	 * @return The min signed long value that can be stored over the specified
	 *         number of bits.
	 * @throws IllegalArgumentException if the specified number of bits is out of
	 *                                  range.
	 */
	public static long minSignedLongForBitSize(int bitSize) {
		checkBitSizeForSignedLong(bitSize);
		return minSignedLongForBitSize_noCheck(bitSize);
	}

	/**
	 * @param bitSize A number of bits in [1,32].
	 * @return The max signed int value that can be stored over the specified number
	 *         of bits.
	 * @throws IllegalArgumentException if the specified number of bits is out of
	 *                                  range.
	 */
	public static int maxSignedIntForBitSize(int bitSize) {
		checkBitSizeForSignedInt(bitSize);
		return maxSignedIntForBitSize_noCheck(bitSize);
	}

	/**
	 * @param bitSize A number of bits in [1,64].
	 * @return The max signed long value that can be stored over the specified
	 *         number of bits.
	 * @throws IllegalArgumentException if the specified number of bits is out of
	 *                                  range.
	 */
	public static long maxSignedLongForBitSize(int bitSize) {
		checkBitSizeForSignedLong(bitSize);
		return maxSignedLongForBitSize_noCheck(bitSize);
	}

	/**
	 * @param bitSize A number of bits in [1,31].
	 * @return The max unsigned int value that can be stored over the specified
	 *         number of bits.
	 * @throws IllegalArgumentException if the specified number of bits is out of
	 *                                  range.
	 */
	public static int maxUnsignedIntForBitSize(int bitSize) {
		checkBitSizeForUnsignedInt(bitSize);
		// i.e. (1<<bitSize)-1
		return (Integer.MAX_VALUE >> (31 - bitSize));
	}

	/**
	 * @param bitSize A number of bits in [1,63].
	 * @return The max unsigned long value that can be stored over the specified
	 *         number of bits.
	 * @throws IllegalArgumentException if the specified number of bits is out of
	 *                                  range.
	 */
	public static long maxUnsignedLongForBitSize(int bitSize) {
		checkBitSizeForUnsignedLong(bitSize);
		// i.e. (1L<<bitSize)-1
		return (Long.MAX_VALUE >> (63 - bitSize));
	}

	/*
	 * 
	 */

	/**
	 * @return The number of bits required to store the specified value as a signed
	 *         integer, i.e. a result in [1,32].
	 */
	public static int bitSizeForSignedValue(int value) {
		if (value > 0) {
			return 33 - Integer.numberOfLeadingZeros(value);
		} else if (value == 0) {
			return 1;
		} else {
			// Works for Integer.MIN_VALUE as well.
			return 33 - Integer.numberOfLeadingZeros(-value - 1);
		}
	}

	/**
	 * @return The number of bits required to store the specified value as a signed
	 *         integer, i.e. a result in [1,64].
	 */
	public static int bitSizeForSignedValue(long value) {
		if (value > 0) {
			return 65 - Long.numberOfLeadingZeros(value);
		} else if (value == 0) {
			return 1;
		} else {
			// Works for Long.MIN_VALUE as well.
			return 65 - Long.numberOfLeadingZeros(-value - 1);
		}
	}

	/**
	 * @param value An integer value in [0,Integer.MAX_VALUE].
	 * @return The number of bits required to store the specified value as an
	 *         unsigned integer, i.e. a result in [1,31].
	 * @throws IllegalArgumentException if the specified value is < 0.
	 */
	public static int bitSizeForUnsignedValue(int value) {
		if (value > 0) {
			return 32 - Integer.numberOfLeadingZeros(value);
		} else {
			if (value == 0) {
				return 1;
			} else {
				throw new IllegalArgumentException("unsigned value [" + value + "] must be >= 0");
			}
		}
	}

	/**
	 * @param value An integer value in [0,Long.MAX_VALUE].
	 * @return The number of bits required to store the specified value as an
	 *         unsigned integer, i.e. a result in [1,63].
	 * @throws IllegalArgumentException if the specified value is < 0.
	 */
	public static int bitSizeForUnsignedValue(long value) {
		if (value > 0) {
			return 64 - Long.numberOfLeadingZeros(value);
		} else {
			if (value == 0) {
				return 1;
			} else {
				throw new IllegalArgumentException("unsigned value [" + value + "] must be >= 0");
			}
		}
	}

	/*
	 * integer functions
	 */

	/**
	 * @return 1 if the specified value is > 0, 0 if it is 0, -1 otherwise.
	 */
	public static int signum(int a) {
		return (a < 0) ? -1 : ((a == 0) ? 0 : 1);
	}

	/**
	 * @return 1 if the specified value is > 0, 0 if it is 0, -1 otherwise.
	 */
	public static int signum(long a) {
		return (a < 0) ? -1 : ((a == 0) ? 0 : 1);
	}

	/**
	 * @return True if the specified value is even, false otherwise.
	 */
	public static boolean isEven(int a) {
		return ((a & 1) == 0);
	}

	/**
	 * @return True if the specified value is even, false otherwise.
	 */
	public static boolean isEven(long a) {
		// faster to work on ints
		return isEven((int) a);
	}

	/**
	 * @return True if the specified value is odd, false otherwise.
	 */
	public static boolean isOdd(int a) {
		return ((a & 1) != 0);
	}

	/**
	 * @return True if the specified value is odd, false otherwise.
	 */
	public static boolean isOdd(long a) {
		// faster to work on ints
		return isOdd((int) a);
	}

	/**
	 * @return True if the specified values are both even or both odd, false
	 *         otherwise.
	 */
	public static boolean haveSameEvenness(int a, int b) {
		return (((a ^ b) & 1) == 0);
	}

	/**
	 * @return True if the specified values are both even or both odd, false
	 *         otherwise.
	 */
	public static boolean haveSameEvenness(long a, long b) {
		// faster to work on ints
		return haveSameEvenness((int) a, (int) b);
	}

	/**
	 * @return True if the specified values are both >= 0 or both < 0, false
	 *         otherwise.
	 */
	public static boolean haveSameSign(int a, int b) {
		return ((a ^ b) >= 0);
	}

	/**
	 * @return True if the specified values are both >= 0 or both < 0, false
	 *         otherwise.
	 */
	public static boolean haveSameSign(long a, long b) {
		return ((a ^ b) >= 0);
	}

	/**
	 * @return True if the specified value is a power of two, i.e. a value of the
	 *         form 2^k, with k >= 0.
	 */
	public static boolean isPowerOfTwo(int a) {
		if (a <= 0) {
			return false;
		}
		if (false) {
			// also works
			return (a & -a) == a;
		}
		return (a & (a - 1)) == 0;
	}

	/**
	 * @return True if the specified value is a power of two, i.e. a value of the
	 *         form 2^k, with k >= 0.
	 */
	public static boolean isPowerOfTwo(long a) {
		if (a <= 0) {
			return false;
		}
		if (false) {
			// also works
			return (a & -a) == a;
		}
		return (a & (a - 1)) == 0;
	}

	/**
	 * @return True if the specified value is a signed power of two, i.e. a value of
	 *         the form +-2^k, with k >= 0.
	 */
	public static boolean isSignedPowerOfTwo(int a) {
		if (a > 0) {
			return (a & (a - 1)) == 0;
		} else {
			if (a == -a) {
				// a is 0 or Integer.MIN_VALUE
				return (a != 0);
			}
			return ((-a) & (-a - 1)) == 0;
		}
	}

	/**
	 * @return True if the specified value is a signed power of two, i.e. a value of
	 *         the form +-2^k, with k >= 0.
	 */
	public static boolean isSignedPowerOfTwo(long a) {
		if (a > 0) {
			return (a & (a - 1)) == 0;
		} else {
			if (a == -a) {
				// a is 0 or Long.MIN_VALUE
				return (a != 0);
			}
			return ((-a) & (-a - 1)) == 0;
		}
	}

	/**
	 * @param a A value in [1,Integer.MAX_VALUE].
	 * @return The highest power of two <= a.
	 */
	public static int floorPowerOfTwo(int a) {
		if (a <= 0) {
			throw new IllegalArgumentException("a [" + a + "] must be > 0");
		}
		return Integer.highestOneBit(a);
	}

	/**
	 * @param a A value in [1,Long.MAX_VALUE].
	 * @return The highest power of two <= a.
	 */
	public static long floorPowerOfTwo(long a) {
		if (a <= 0) {
			throw new IllegalArgumentException("a [" + a + "] must be > 0");
		}
		// Faster than copying int method
		// (less computations on long).
		return 1L << (63 - Long.numberOfLeadingZeros(a));
	}

	/**
	 * @param a A value in [0,2^30].
	 * @return The lowest power of two >= a.
	 */
	public static int ceilingPowerOfTwo(int a) {
		checkIsInRange(0, (1 << 30), a);
		return (a >= 2) ? Integer.highestOneBit((a - 1) << 1) : 1;
	}

	/**
	 * @param a A value in [0,2^62].
	 * @return The lowest power of two >= a.
	 */
	public static long ceilingPowerOfTwo(long a) {
		checkIsInRange(0L, (1L << 62), a);
		// Faster than copying int method
		// (less computations on long).
		return 1L << (64 - Long.numberOfLeadingZeros(a - 1));
	}

	/**
	 * @return Mean without overflow, rounded to the lowest value (i.e. mathematical
	 *         floor((a+b)/2), using floating point division).
	 */
	public static int meanLow(int a, int b) {
		return (a & b) + ((a ^ b) >> 1);
	}

	/**
	 * @return Mean without overflow, rounded to the lowest value (i.e. mathematical
	 *         floor((a+b)/2), using floating point division).
	 */
	public static long meanLow(long a, long b) {
		return (a & b) + ((a ^ b) >> 1);
	}

	/**
	 * @return Mean without overflow, rounded to the value of smallest magnitude
	 *         (i.e. mathematical (a+b)/2, using integer division).
	 */
	public static int meanSml(int a, int b) {
		int result = meanLow(a, b);
		if (!haveSameEvenness(a, b)) {
			// inexact
			if (((a & b) < 0) || (((a | b) < 0) && (a + b < 0))) {
				// both < 0, or only one is < 0 and it has the largest magnitude
				result++;
			}
		}
		return result;
	}

	/**
	 * @return Mean without overflow, rounded to the value of smallest magnitude
	 *         (i.e. mathematical (a+b)/2, using integer division).
	 */
	public static long meanSml(long a, long b) {
		long result = meanLow(a, b);
		if (!haveSameEvenness(a, b)) {
			// inexact
			if (((a & b) < 0) || (((a | b) < 0) && (a + b < 0))) {
				// both < 0, or only one is < 0 and it has the largest magnitude
				result++;
			}
		}
		return result;
	}

	/**
	 * Useful because a positive int value could not represent half the width of
	 * full int range width, which is mathematically Integer.MAX_VALUE+1.
	 * 
	 * @return Minus half the range width (inclusive, and rounded to the value of
	 *         smaller magnitude) between the specified bounds.
	 * @throws IllegalArgumentException if min > max.
	 */
	public static int negHalfWidth(int min, int max) {
		if (min > max) {
			throw new IllegalArgumentException("min [" + min + "] must be <= max [" + max + "]");
		}
		int mean = meanLow(min, max);
		return min - mean - ((min ^ max) & 1);
	}

	/**
	 * Useful because a positive long value could not represent half the width of
	 * full long range width, which is mathematically Long.MAX_VALUE+1.
	 * 
	 * @return Minus half the range width (inclusive, and rounded to the value of
	 *         smaller magnitude) between the specified bounds.
	 * @throws IllegalArgumentException if min > max.
	 */
	public static long negHalfWidth(long min, long max) {
		if (min > max) {
			throw new IllegalArgumentException("min [" + min + "] must be <= max [" + max + "]");
		}
		long mean = meanLow(min, max);
		return min - mean - ((min ^ max) & 1);
	}

	/**
	 * This treatment being designed for optimization, the fact that spot is a
	 * signed power of two is not checked.
	 * 
	 * @param value A value.
	 * @param spot  A signed power of two (i.e. a value of the form +-2^k, k >= 0).
	 * @return value % spot, i.e. a value in ]-|spot|,|spot|[.
	 */
	public static int moduloSignedPowerOfTwo(int value, int spot) {
		if (spot == Integer.MIN_VALUE) {
			return (value != Integer.MIN_VALUE) ? value : 0;
		} else {
			int s = (value >> 31);
			return ((((value + s) ^ s) & (abs(spot) - 1)) + s) ^ s;
		}
	}

	/**
	 * This treatment being designed for optimization, the fact that spot is a
	 * signed power of two is not checked.
	 * 
	 * @param value A value.
	 * @param spot  A signed power of two (i.e. a value of the form +-2^k, k >= 0).
	 * @return value % spot, i.e. a value in ]-|spot|,|spot|[.
	 */
	public static long moduloSignedPowerOfTwo(long value, long spot) {
		if (spot == Long.MIN_VALUE) {
			return (value != Long.MIN_VALUE) ? value : 0;
		} else {
			long s = (value >> 63);
			return ((((value + s) ^ s) & (abs(spot) - 1)) + s) ^ s;
		}
	}

	/**
	 * @param value An integer value > 0.
	 * @return The integer part of the logarithm, in base 2, of the specified value,
	 *         i.e. a result in [0,30]
	 * @throws IllegalArgumentException if the specified value is <= 0.
	 */
	public static int log2(int value) {
		if (value <= 0) {
			throw new IllegalArgumentException("value [" + value + "] must be > 0");
		}
		return 31 - Integer.numberOfLeadingZeros(value);
	}

	/**
	 * @param value An integer value > 0.
	 * @return The integer part of the logarithm, in base 2, of the specified value,
	 *         i.e. a result in [0,62]
	 * @throws IllegalArgumentException if the specified value is <= 0.
	 */
	public static int log2(long value) {
		if (value <= 0) {
			throw new IllegalArgumentException("value [" + value + "] must be > 0");
		}
		return 63 - Long.numberOfLeadingZeros(value);
	}

	/**
	 * Possibly faster than java.lang.Math.abs(int).
	 * 
	 * @return The absolute value, except if value is Integer.MIN_VALUE, for which
	 *         it returns Integer.MIN_VALUE.
	 */
	public static int abs(int a) {
		return (a ^ (a >> 31)) - (a >> 31);
	}

	/**
	 * Possibly faster than java.lang.Math.abs(long).
	 * 
	 * @return The absolute value, except if value is Long.MIN_VALUE, for which it
	 *         returns Long.MIN_VALUE.
	 */
	public static long abs(long a) {
		return (a ^ (a >> 63)) - (a >> 63);
	}

	/**
	 * @return The negative of the absolute value (always exact).
	 */
	public static int absNeg(int a) {
		return (a >> 31) - (a ^ (a >> 31));
	}

	/**
	 * @return The negative of the absolute value (always exact).
	 */
	public static long absNeg(long a) {
		return (a >> 63) - (a ^ (a >> 63));
	}

	/**
	 * If the specified value is in int range, the returned value is identical.
	 * 
	 * @return An int hash of the specified value.
	 */
	public static int intHash(long a) {
		if (false) {
			// also works
			int hash = ((int) (a >> 32)) ^ ((int) a);
			if (a < 0) {
				hash = -hash - 1;
			}
			return hash;
		}
		int hash = ((int) (a >> 32)) + ((int) a);
		if (a < 0) {
			hash++;
		}
		return hash;
	}

	/**
	 * Not defining an asByte(long) method, since asByte((int)aLong) works.
	 * 
	 * @param a An int value.
	 * @return The specified value as byte.
	 * @throws ArithmeticException if the specified value is not in
	 *                             [Byte.MIN_VALUE,Byte.MAX_VALUE] range.
	 */
	public static byte asByte(int a) {
		if (a != (byte) a) {
			throw new ArithmeticException("overflow: " + a);
		}
		return (byte) a;
	}

	/**
	 * @param a A long value.
	 * @return The specified value as int.
	 * @throws ArithmeticException if the specified value is not in
	 *                             [Integer.MIN_VALUE,Integer.MAX_VALUE] range.
	 */
	public static int asInt(long a) {
		if (a != (int) a) {
			throw new ArithmeticException("overflow: " + a);
		}
		return (int) a;
	}

	/**
	 * @param a A long value.
	 * @return The closest int value in [Integer.MIN_VALUE,Integer.MAX_VALUE] range.
	 */
	public static int toInt(long a) {
		if (a != (int) a) {
			return (a < 0) ? Integer.MIN_VALUE : Integer.MAX_VALUE;
		}
		return (int) a;
	}

	/**
	 * @param a An int value.
	 * @param b An int value.
	 * @return The mathematical result of a+b.
	 * @throws ArithmeticException if the mathematical result of a+b is not in
	 *                             [Integer.MIN_VALUE,Integer.MAX_VALUE] range.
	 */
	public static int plusExact(int a, int b) {
		final int sum = a + b;
		// HD 2-12 Overflow iff both arguments
		// have the opposite sign of the result.
		if (((a ^ sum) & (b ^ sum)) < 0) {
			throw new ArithmeticException("overflow: " + a + "+" + b);
		}
		return sum;
	}

	/**
	 * @param a A long value.
	 * @param b A long value.
	 * @return The mathematical result of a+b.
	 * @throws ArithmeticException if the mathematical result of a+b is not in
	 *                             [Long.MIN_VALUE,Long.MAX_VALUE] range.
	 */
	public static long plusExact(long a, long b) {
		final long sum = a + b;
		// HD 2-12 Overflow iff both arguments
		// have the opposite sign of the result.
		if (((a ^ sum) & (b ^ sum)) < 0) {
			throw new ArithmeticException("overflow: " + a + "+" + b);
		}
		return sum;
	}

	/**
	 * @param a An int value.
	 * @param b An int value.
	 * @return The int value of [Integer.MIN_VALUE,Integer.MAX_VALUE] range which is
	 *         the closest to mathematical result of a+b.
	 */
	public static int plusBounded(int a, int b) {
		return toInt(((long) a) + ((long) b));
	}

	/**
	 * @param a A long value.
	 * @param b A long value.
	 * @return The long value of [Long.MIN_VALUE,Long.MAX_VALUE] range which is the
	 *         closest to mathematical result of a+b.
	 */
	public static long plusBounded(long a, long b) {
		final long sum = a + b;
		if (((a ^ sum) & (b ^ sum)) < 0) {
			return (sum >= 0) ? Long.MIN_VALUE : Long.MAX_VALUE;
		}
		return sum;
	}

	/**
	 * @param a An int value.
	 * @param b An int value.
	 * @return The mathematical result of a-b.
	 * @throws ArithmeticException if the mathematical result of a-b is not in
	 *                             [Integer.MIN_VALUE,Integer.MAX_VALUE] range.
	 */
	public static int minusExact(int a, int b) {
		final int diff = a - b;
		// HD 2-12 Overflow iff the arguments have different signs and
		// the sign of the result is different than the sign of "a".
		if (((a ^ b) & (a ^ diff)) < 0) {
			throw new ArithmeticException("integer overflow");
		}
		return diff;
	}

	/**
	 * @param a A long value.
	 * @param b A long value.
	 * @return The mathematical result of a-b.
	 * @throws ArithmeticException if the mathematical result of a-b is not in
	 *                             [Long.MIN_VALUE,Long.MAX_VALUE] range.
	 */
	public static long minusExact(long a, long b) {
		final long diff = a - b;
		// HD 2-12 Overflow iff the arguments have different signs and
		// the sign of the result is different than the sign of "a".
		if (((a ^ b) & (a ^ diff)) < 0) {
			throw new ArithmeticException("integer overflow");
		}
		return diff;
	}

	/**
	 * @param a An int value.
	 * @param b An int value.
	 * @return The int value of [Integer.MIN_VALUE,Integer.MAX_VALUE] range which is
	 *         the closest to mathematical result of a-b.
	 */
	public static int minusBounded(int a, int b) {
		return toInt(((long) a) - ((long) b));
	}

	/**
	 * @param a A long value.
	 * @param b A long value.
	 * @return The long value of [Long.MIN_VALUE,Long.MAX_VALUE] range which is the
	 *         closest to mathematical result of a-b.
	 */
	public static long minusBounded(long a, long b) {
		final long diff = a - b;
		if (((a ^ b) & (a ^ diff)) < 0) {
			return (diff >= 0) ? Long.MIN_VALUE : Long.MAX_VALUE;
		}
		return diff;
	}

	/**
	 * @param a An int value.
	 * @param b An int value.
	 * @return The mathematical result of a*b.
	 * @throws ArithmeticException if the mathematical result of a*b is not in
	 *                             [Integer.MIN_VALUE,Integer.MAX_VALUE] range.
	 */
	public static int timesExact(int a, int b) {
		final long prod = a * (long) b;
		if (prod != (int) prod) {
			throw new ArithmeticException("overflow: " + a + "*" + b);
		}
		return (int) prod;
	}

	/**
	 * @param a A long value.
	 * @param b A long value.
	 * @return The mathematical result of a*b.
	 * @throws ArithmeticException if the mathematical result of a*b is not in
	 *                             [Long.MIN_VALUE,Long.MAX_VALUE] range.
	 */
	public static long timesExact(long a, long b) {
		final long prod = a * b;
		final long absA = abs(a);
		final long absB = abs(b);
		if (((absA | absB) >>> 31) != 0) {
			// Some bits greater than 2^31 that might cause overflow
			// Check the result using the divide operator
			// and check for the special case of Long.MIN_VALUE * -1
			if (((b != 0) && (prod / b != a)) || ((a == Long.MIN_VALUE) && (b == -1))) {
				throw new ArithmeticException("overflow: " + a + "*" + b);
			}
		}
		return prod;
	}

	/**
	 * @param a An int value.
	 * @param b An int value.
	 * @return The int value of [Integer.MIN_VALUE,Integer.MAX_VALUE] range which is
	 *         the closest to mathematical result of a*b.
	 */
	public static int timesBounded(int a, int b) {
		return (int) (a * (double) b);
	}

	/**
	 * @param a A long value.
	 * @param b A long value.
	 * @return The long value of [Long.MIN_VALUE,Long.MAX_VALUE] range which is the
	 *         closest to mathematical result of a*b.
	 */
	public static long timesBounded(long a, long b) {
		final long prod = a * b;
		final long absA = abs(a);
		final long absB = abs(b);
		if (((absA | absB) >>> 31) != 0) {
			// Some bits greater than 2^31 that might cause overflow
			// Check the result using the divide operator
			// and check for the special case of Long.MIN_VALUE * -1
			if (((b != 0) && (prod / b != a)) || ((a == Long.MIN_VALUE) && (b == -1))) {
				return ((a ^ b) >= 0) ? Long.MAX_VALUE : Long.MIN_VALUE;
			}
		}
		return prod;
	}

	/*
	 * powers
	 */

	/**
	 * Returns the exact result, provided it's in double range, i.e. if power is in
	 * [-1074,1023].
	 * 
	 * @param power An int power.
	 * @return 2^power as a double, or +-Infinity in case of overflow.
	 */
	public static double twoPow(int power) {
		if (power <= -MAX_DOUBLE_EXPONENT) { // Not normal.
			if (power >= MIN_DOUBLE_EXPONENT) { // Subnormal.
				return Double.longBitsToDouble(0x0008000000000000L >> (-(power + MAX_DOUBLE_EXPONENT)));
			} else { // Underflow.
				return 0.0;
			}
		} else if (power > MAX_DOUBLE_EXPONENT) { // Overflow.
			return Double.POSITIVE_INFINITY;
		} else { // Normal.
			return Double.longBitsToDouble(((long) (power + MAX_DOUBLE_EXPONENT)) << 52);
		}
	}

	/**
	 * @param power An int power.
	 * @return 2^power as an int.
	 * @throws ArithmeticException if the mathematical result is not in int range,
	 *                             i.e. if power is not in [0,30].
	 */
	public static int twoPowAsIntExact(int power) {
		if ((power < 0) || (power > 30)) {
			throw new ArithmeticException("integer overflow");
		}
		return 1 << power;
	}

	/**
	 * @param power An int power.
	 * @return 2^power as an int, or the closest power of two in int range in case
	 *         of overflow, i.e. if power is not in [0,30].
	 */
	public static int twoPowAsIntBounded(int power) {
		power = toRange(0, 30, power);
		return 1 << power;
	}

	/**
	 * @param power An int power.
	 * @return 2^power as a long.
	 * @throws ArithmeticException if the mathematical result is not in long range,
	 *                             i.e. if power is not in [0,62].
	 */
	public static long twoPowAsLongExact(int power) {
		if ((power < 0) || (power > 62)) {
			throw new ArithmeticException("long overflow");
		}
		return 1L << power;
	}

	/**
	 * @param power An int power.
	 * @return 2^power as a long, or the closest power of two in long range in case
	 *         of overflow, i.e. if power is not in [0,62].
	 */
	public static long twoPowAsLongBounded(int power) {
		power = toRange(0, 62, power);
		return 1L << power;
	}

	/**
	 * @param a A value.
	 * @return a*a.
	 */
	public static int pow2(int a) {
		return a * a;
	}

	/**
	 * @param a A value.
	 * @return a*a.
	 */
	public static long pow2(long a) {
		return a * a;
	}

	/**
	 * @param a A value.
	 * @return a*a.
	 */
	public static float pow2(float a) {
		return a * a;
	}

	/**
	 * Strict version.
	 * 
	 * @param a A value.
	 * @return a*a.
	 */
	public static strictfp float pow2_strict(float a) {
		return a * a;
	}

	/**
	 * @param a A value.
	 * @return a*a.
	 */
	public static double pow2(double a) {
		return a * a;
	}

	/**
	 * Strict version.
	 * 
	 * @param a A value.
	 * @return a*a.
	 */
	public static strictfp double pow2_strict(double a) {
		return a * a;
	}

	/**
	 * @param a A value.
	 * @return a*a*a.
	 */
	public static int pow3(int a) {
		return a * a * a;
	}

	/**
	 * @param a A value.
	 * @return a*a*a.
	 */
	public static long pow3(long a) {
		return a * a * a;
	}

	/**
	 * @param a A value.
	 * @return a*a*a.
	 */
	public static float pow3(float a) {
		return a * a * a;
	}

	/**
	 * Strict version.
	 * 
	 * @param a A value.
	 * @return a*a*a.
	 */
	public static strictfp float pow3_strict(float a) {
		return a * a * a;
	}

	/**
	 * @param a A value.
	 * @return a*a*a.
	 */
	public static double pow3(double a) {
		return a * a * a;
	}

	/**
	 * Strict version.
	 * 
	 * @param a A value.
	 * @return a*a*a.
	 */
	public static strictfp double pow3_strict(double a) {
		return a * a * a;
	}

	/*
	 * Accurate +-m*PI/n.
	 */

	/**
	 * @param angRad An angle, in radians.
	 * @return angRad + 2*PI, accurately computed.
	 */
	public static double plus2PI(double angRad) {
		if (angRad > -Math.PI) {
			// LO then HI, for better accuracy (if starting near 0).
			return (angRad + TWOPI_LO) + TWOPI_HI;
		} else {
			// HI then LO, for better accuracy (if ending near 0).
			return (angRad + TWOPI_HI) + TWOPI_LO;
		}
	}

	/**
	 * Strict version.
	 * 
	 * @param angRad An angle, in radians.
	 * @return angRad + 2*PI, accurately computed.
	 */
	public static strictfp double plus2PI_strict(double angRad) {
		if (angRad > -Math.PI) {
			// LO then HI, for better accuracy (if starting near 0).
			return (angRad + TWOPI_LO) + TWOPI_HI;
		} else {
			// HI then LO, for better accuracy (if ending near 0).
			return (angRad + TWOPI_HI) + TWOPI_LO;
		}
	}

	/**
	 * @param angRad An angle, in radians.
	 * @return angRad - 2*PI, accurately computed.
	 */
	public static double minus2PI(double angRad) {
		if (angRad < Math.PI) {
			// LO then HI, for better accuracy (if starting near 0).
			return (angRad - TWOPI_LO) - TWOPI_HI;
		} else {
			// HI then LO, for better accuracy (if ending near 0).
			return (angRad - TWOPI_HI) - TWOPI_LO;
		}
	}

	/**
	 * Strict version.
	 * 
	 * @param angRad An angle, in radians.
	 * @return angRad - 2*PI, accurately computed.
	 */
	public static strictfp double minus2PI_strict(double angRad) {
		if (angRad < Math.PI) {
			// LO then HI, for better accuracy (if starting near 0).
			return (angRad - TWOPI_LO) - TWOPI_HI;
		} else {
			// HI then LO, for better accuracy (if ending near 0).
			return (angRad - TWOPI_HI) - TWOPI_LO;
		}
	}

	/**
	 * @param angRad An angle, in radians.
	 * @return angRad + PI, accurately computed.
	 */
	public static double plusPI(double angRad) {
		if (angRad > -Math.PI / 2) {
			// LO then HI, for better accuracy (if starting near 0).
			return (angRad + PI_LO) + PI_HI;
		} else {
			// HI then LO, for better accuracy (if ending near 0).
			return (angRad + PI_HI) + PI_LO;
		}
	}

	/**
	 * Strict version.
	 * 
	 * @param angRad An angle, in radians.
	 * @return angRad + PI, accurately computed.
	 */
	public static strictfp double plusPI_strict(double angRad) {
		if (angRad > -Math.PI / 2) {
			// LO then HI, for better accuracy (if starting near 0).
			return (angRad + PI_LO) + PI_HI;
		} else {
			// HI then LO, for better accuracy (if ending near 0).
			return (angRad + PI_HI) + PI_LO;
		}
	}

	/**
	 * @param angRad An angle, in radians.
	 * @return angRad - PI, accurately computed.
	 */
	public static double minusPI(double angRad) {
		if (angRad < Math.PI / 2) {
			// LO then HI, for better accuracy (if starting near 0).
			return (angRad - PI_LO) - PI_HI;
		} else {
			// HI then LO, for better accuracy (if ending near 0).
			return (angRad - PI_HI) - PI_LO;
		}
	}

	/**
	 * Strict version.
	 * 
	 * @param angRad An angle, in radians.
	 * @return angRad - PI, accurately computed.
	 */
	public static strictfp double minusPI_strict(double angRad) {
		if (angRad < Math.PI / 2) {
			// LO then HI, for better accuracy (if starting near 0).
			return (angRad - PI_LO) - PI_HI;
		} else {
			// HI then LO, for better accuracy (if ending near 0).
			return (angRad - PI_HI) - PI_LO;
		}
	}

	/**
	 * @param angRad An angle, in radians.
	 * @return angRad + PI/2, accurately computed.
	 */
	public static double plusPIO2(double angRad) {
		if (angRad > -Math.PI / 4) {
			// LO then HI, for better accuracy (if starting near 0).
			return (angRad + PIO2_LO) + PIO2_HI;
		} else {
			// HI then LO, for better accuracy (if ending near 0).
			return (angRad + PIO2_HI) + PIO2_LO;
		}
	}

	/**
	 * Strict version.
	 * 
	 * @param angRad An angle, in radians.
	 * @return angRad + PI/2, accurately computed.
	 */
	public static strictfp double plusPIO2_strict(double angRad) {
		if (angRad > -Math.PI / 4) {
			// LO then HI, for better accuracy (if starting near 0).
			return (angRad + PIO2_LO) + PIO2_HI;
		} else {
			// HI then LO, for better accuracy (if ending near 0).
			return (angRad + PIO2_HI) + PIO2_LO;
		}
	}

	/**
	 * @param angRad An angle, in radians.
	 * @return angRad - PI/2, accurately computed.
	 */
	public static double minusPIO2(double angRad) {
		if (angRad < Math.PI / 4) {
			// LO then HI, for better accuracy (if starting near 0).
			return (angRad - PIO2_LO) - PIO2_HI;
		} else {
			// HI then LO, for better accuracy (if ending near 0).
			return (angRad - PIO2_HI) - PIO2_LO;
		}
	}

	/**
	 * Strict version.
	 * 
	 * @param angRad An angle, in radians.
	 * @return angRad - PI/2, accurately computed.
	 */
	public static strictfp double minusPIO2_strict(double angRad) {
		if (angRad < Math.PI / 4) {
			// LO then HI, for better accuracy (if starting near 0).
			return (angRad - PIO2_LO) - PIO2_HI;
		} else {
			// HI then LO, for better accuracy (if ending near 0).
			return (angRad - PIO2_HI) - PIO2_LO;
		}
	}

	/*
	 * toString (radix)
	 */

	/**
	 * @param radix Radix to be checked.
	 * @return True if does not throw.
	 * @throws IllegalArgumentException if the specified radix is not in [2,36].
	 */
	public static boolean checkRadix(int radix) {
		if (!isInRange(Character.MIN_RADIX, Character.MAX_RADIX, radix)) {
			throw new IllegalArgumentException("radix [" + radix + "] must be in [" + Character.MIN_RADIX + "," + Character.MAX_RADIX + "]");
		}
		return true;
	}

	/**
	 * @param radix A radix in [2,36].
	 * @return Number of characters (minus sign included) to represent the specified
	 *         value in the specified radix.
	 */
	public static int computeNbrOfChars(int value, int radix) {
		if (value < 0) {
			// 1 for sign
			return 1 + computeNbrOfDigits_negValue(value, radix);
		} else {
			return computeNbrOfDigits_negValue(-value, radix);
		}
	}

	/**
	 * @param radix A radix in [2,36].
	 * @return Number of characters (minus sign included) to represent the specified
	 *         value in the specified radix.
	 */
	public static int computeNbrOfChars(long value, int radix) {
		if (value < 0) {
			// 1 for sign
			return 1 + computeNbrOfDigits_negValue(value, radix);
		} else {
			return computeNbrOfDigits_negValue(-value, radix);
		}
	}

	/**
	 * @param radix       A radix in [2,36].
	 * @param paddingUpTo Number of digits (sign excluded) up to which left-padding
	 *                    with zeros is done.
	 * @return Number of characters (minus sign included) to represent the specified
	 *         value in the specified radix.
	 */
	public static int computeNbrOfChars(int value, int radix, int paddingUpTo) {
		if (value < 0) {
			// 1 for sign
			return 1 + Math.max(paddingUpTo, computeNbrOfDigits_negValue(value, radix));
		} else {
			return Math.max(paddingUpTo, computeNbrOfDigits_negValue(-value, radix));
		}
	}

	/**
	 * @param radix       A radix in [2,36].
	 * @param paddingUpTo Number of digits (sign excluded) up to which left-padding
	 *                    with zeros is done.
	 * @return Number of characters (minus sign included) to represent the specified
	 *         value in the specified radix.
	 */
	public static int computeNbrOfChars(long value, int radix, int paddingUpTo) {
		if (value < 0) {
			// 1 for sign
			return 1 + Math.max(paddingUpTo, computeNbrOfDigits_negValue(value, radix));
		} else {
			return Math.max(paddingUpTo, computeNbrOfDigits_negValue(-value, radix));
		}
	}

	/**
	 * @param radix A radix in [2,36].
	 * @return Number of digits of the specified value in the specified radix.
	 */
	public static int computeNbrOfDigits(int value, int radix) {
		return computeNbrOfDigits_negValue(-abs(value), radix);
	}

	/**
	 * @param radix A radix in [2,36].
	 * @return Number of digits of the specified value in the specified radix.
	 */
	public static int computeNbrOfDigits(long value, int radix) {
		return computeNbrOfDigits_negValue(-abs(value), radix);
	}

	/**
	 * @param radix       A radix in [2,36].
	 * @param paddingUpTo Number of digits (sign excluded) up to which left-padding
	 *                    with zeros is done.
	 * @return Number of digits of the specified value in the specified radix,
	 *         including the specified padding.
	 */
	public static int computeNbrOfDigits(int value, int radix, int paddingUpTo) {
		return Math.max(paddingUpTo, computeNbrOfDigits(value, radix));
	}

	/**
	 * @param radix       A radix in [2,36].
	 * @param paddingUpTo Number of digits (sign excluded) up to which left-padding
	 *                    with zeros is done.
	 * @return Number of digits of the specified value in the specified radix,
	 *         including the specified padding.
	 */
	public static int computeNbrOfDigits(long value, int radix, int paddingUpTo) {
		return Math.max(paddingUpTo, computeNbrOfDigits(value, radix));
	}

	/**
	 * This method just delegates to Integer.toString(int), but is defined here to
	 * complete the API.
	 * 
	 * @return String representation of the specified value in base 10.
	 */
	public static String toString(int value) {
		return Integer.toString(value);
	}

	/**
	 * This method just delegates to Long.toString(long), but is defined here to
	 * complete the API.
	 * 
	 * @return String representation of the specified value in base 10.
	 */
	public static String toString(long value) {
		return Long.toString(value);
	}

	/**
	 * @param radix A radix in [2,36].
	 * @return String representation of the specified value in the specified radix.
	 * @throws IllegalArgumentException if the specified radix is out of range.
	 */
	public static String toString(int value, int radix) {
		return toString(value, radix, 0);
	}

	/**
	 * @param radix A radix in [2,36].
	 * @return String representation of the specified value in the specified radix.
	 * @throws IllegalArgumentException if the specified radix is out of range.
	 */
	public static String toString(long value, int radix) {
		return toString(value, radix, 0);
	}

	/**
	 * @param radix       A radix in [2,36].
	 * @param paddingUpTo Number of digits (sign excluded) up to which left-padding
	 *                    with zeros is done.
	 * @return String representation of the specified value in the specified radix.
	 * @throws IllegalArgumentException if the specified radix is out of range.
	 */
	public static String toString(int value, int radix, int paddingUpTo) {
		// Only one test if radix+paddingUpTo != 10.
		if ((radix + paddingUpTo == 10) && (paddingUpTo == 0)) {
			// Using JDK's optimized algorithm.
			return Integer.toString(value);
		}

		int negValue;
		final int signSize;
		final boolean negative = (value < 0);
		if (negative) {
			negValue = value;
			signSize = 1;
		} else {
			negValue = -value;
			signSize = 0;
		}
		// Faster if we just use max possible number of characters (33),
		// but we prefer to take care of garbage's memory footprint.
		// Checks radix.
		final int nbrOfChars = signSize + Math.max(paddingUpTo, computeNbrOfDigits_negValue(negValue, radix));

		final char[] chars = new char[nbrOfChars];

		int charPos = nbrOfChars;

		final boolean radixIsPowerOfTwo = ((radix & (radix - 1)) == 0);
		// Not allowing Integer.MIN_VALUE so it can be negated.
		if (radixIsPowerOfTwo && (negValue != Integer.MIN_VALUE)) {
			final int mask = radix - 1;
			final int divShift = DIV_SHIFT_BY_RADIX[radix];
			while (negValue <= -radix) {
				chars[--charPos] = CHAR_BY_DIGIT[(int) ((-negValue) & mask)];
				negValue = -((-negValue) >> divShift);
			}
		} else {
			while (negValue <= -radix) {
				chars[--charPos] = CHAR_BY_DIGIT[(int) (-(negValue % radix))];
				negValue /= radix;
			}
		}
		chars[--charPos] = CHAR_BY_DIGIT[(int) (-negValue)];

		while (charPos > signSize) {
			chars[--charPos] = '0';
		}

		if (negative) {
			chars[0] = '-';
		}

		return new String(chars);
	}

	/**
	 * @param radix       A radix in [2,36].
	 * @param paddingUpTo Number of digits (sign excluded) up to which left-padding
	 *                    with zeros is done.
	 * @return String representation of the specified value in the specified radix.
	 * @throws IllegalArgumentException if the specified radix is out of range.
	 */
	public static String toString(long value, int radix, int paddingUpTo) {
		// Only one test if radix+paddingUpTo != 10.
		if ((radix + paddingUpTo == 10) && (paddingUpTo == 0)) {
			// Using JDK's optimized algorithm.
			return Long.toString(value);
		}

		long negValue;
		final int signSize;
		final boolean negative = (value < 0);
		if (negative) {
			negValue = value;
			signSize = 1;
		} else {
			negValue = -value;
			signSize = 0;
		}
		// Checks radix.
		final int nbrOfChars = signSize + Math.max(paddingUpTo, computeNbrOfDigits_negValue(negValue, radix));

		final char[] chars = new char[nbrOfChars];

		int charPos = nbrOfChars;

		final boolean radixIsPowerOfTwo = ((radix & (radix - 1)) == 0);
		// Not allowing Long.MIN_VALUE so it can be negated.
		if (radixIsPowerOfTwo && (negValue != Long.MIN_VALUE)) {
			final int mask = radix - 1;
			final int divShift = DIV_SHIFT_BY_RADIX[radix];
			while (negValue <= -radix) {
				chars[--charPos] = CHAR_BY_DIGIT[(int) ((-negValue) & mask)];
				negValue = -((-negValue) >> divShift);
			}
		} else {
			while (negValue <= -radix) {
				chars[--charPos] = CHAR_BY_DIGIT[(int) (-(negValue % radix))];
				negValue /= radix;
			}
		}
		chars[--charPos] = CHAR_BY_DIGIT[(int) (-negValue)];

		while (charPos > signSize) {
			chars[--charPos] = '0';
		}

		if (negative) {
			chars[0] = '-';
		}

		return new String(chars);
	}

	/*
	 * toString (bits)
	 */

	/**
	 * @param firstBitPos    First bit position (inclusive).
	 * @param lastBitPosExcl Last bit position (exclusive).
	 * @return True if does not throw.
	 * @throws IllegalArgumentException if the specified bit range does not fit in a
	 *                                  byte.
	 */
	public static boolean checkBitPositionsByte(int firstBitPos, int lastBitPosExcl) {
		return checkBitPositions(firstBitPos, lastBitPosExcl, 8);
	}

	/**
	 * @param firstBitPos    First bit position (inclusive).
	 * @param lastBitPosExcl Last bit position (exclusive).
	 * @return True if does not throw.
	 * @throws IllegalArgumentException if the specified bit range does not fit in a
	 *                                  short.
	 */
	public static boolean checkBitPositionsShort(int firstBitPos, int lastBitPosExcl) {
		return checkBitPositions(firstBitPos, lastBitPosExcl, 16);
	}

	/**
	 * @param firstBitPos    First bit position (inclusive).
	 * @param lastBitPosExcl Last bit position (exclusive).
	 * @return True if does not throw.
	 * @throws IllegalArgumentException if the specified bit range does not fit in
	 *                                  an int.
	 */
	public static boolean checkBitPositionsInt(int firstBitPos, int lastBitPosExcl) {
		return checkBitPositions(firstBitPos, lastBitPosExcl, 32);
	}

	/**
	 * @param firstBitPos    First bit position (inclusive).
	 * @param lastBitPosExcl Last bit position (exclusive).
	 * @return True if does not throw.
	 * @throws IllegalArgumentException if the specified bit range does not fit in a
	 *                                  long.
	 */
	public static boolean checkBitPositionsLong(int firstBitPos, int lastBitPosExcl) {
		return checkBitPositions(firstBitPos, lastBitPosExcl, 64);
	}

	/**
	 * @return String representation of specified bits, in big endian.
	 */
	public static String toStringBits(byte bits) {
		final char[] chars = new char[8];
		int bitIndex = 8;
		while (--bitIndex >= 0) {
			chars[7 - bitIndex] = (char) ('0' + ((bits >> bitIndex) & 1));
		}
		return new String(chars);
	}

	/**
	 * @return String representation of specified bits, in big endian.
	 */
	public static String toStringBits(short bits) {
		final char[] chars = new char[16];
		int bitIndex = 16;
		while (--bitIndex >= 0) {
			chars[15 - bitIndex] = (char) ('0' + ((bits >> bitIndex) & 1));
		}
		return new String(chars);
	}

	/**
	 * @return String representation of specified bits, in big endian.
	 */
	public static String toStringBits(int bits) {
		final char[] chars = new char[32];
		int bitIndex = 32;
		while (--bitIndex >= 0) {
			chars[31 - bitIndex] = (char) ('0' + ((bits >> bitIndex) & 1));
		}
		return new String(chars);
	}

	/**
	 * @return String representation of specified bits, in big endian.
	 */
	public static String toStringBits(long bits) {
		final char[] chars = new char[64];
		int bitIndex = 64;
		while (--bitIndex >= 0) {
			chars[63 - bitIndex] = (char) ('0' + ((bits >> bitIndex) & 1));
		}
		return new String(chars);
	}

	/**
	 * @param firstBitPos    First bit position (inclusive).
	 * @param lastBitPosExcl Last bit position (exclusive).
	 * @param bigEndian      True for bits to be added in big endian order (MSBit to
	 *                       LSBit) false for little endian order.
	 * @param padding        True if underscores must be added instead of
	 *                       out-of-range bits, false to just add characters
	 *                       corresponding to in-range bits.
	 * @return String representation of specified bits.
	 */
	public static String toStringBits(byte bits, int firstBitPos, int lastBitPosExcl, boolean bigEndian, boolean padding) {
		checkBitPositionsByte(firstBitPos, lastBitPosExcl);
		return toStringBits_0_32_bitPosAlreadyChecked(8, bits, firstBitPos, lastBitPosExcl, bigEndian, padding);
	}

	/**
	 * @param firstBitPos    First bit position (inclusive).
	 * @param lastBitPosExcl Last bit position (exclusive).
	 * @param bigEndian      True for bits to be added in big endian order (MSBit to
	 *                       LSBit) false for little endian order.
	 * @param padding        True if underscores must be added instead of
	 *                       out-of-range bits, false to just add characters
	 *                       corresponding to in-range bits.
	 * @return String representation of specified bits.
	 */
	public static String toStringBits(short bits, int firstBitPos, int lastBitPosExcl, boolean bigEndian, boolean padding) {
		checkBitPositionsShort(firstBitPos, lastBitPosExcl);
		return toStringBits_0_32_bitPosAlreadyChecked(16, bits, firstBitPos, lastBitPosExcl, bigEndian, padding);
	}

	/**
	 * @param firstBitPos    First bit position (inclusive).
	 * @param lastBitPosExcl Last bit position (exclusive).
	 * @param bigEndian      True for bits to be added in big endian order (MSBit to
	 *                       LSBit) false for little endian order.
	 * @param padding        True if underscores must be added instead of
	 *                       out-of-range bits, false to just add characters
	 *                       corresponding to in-range bits.
	 * @return String representation of specified bits.
	 */
	public static String toStringBits(int bits, int firstBitPos, int lastBitPosExcl, boolean bigEndian, boolean padding) {
		checkBitPositionsInt(firstBitPos, lastBitPosExcl);
		return toStringBits_0_32_bitPosAlreadyChecked(32, bits, firstBitPos, lastBitPosExcl, bigEndian, padding);
	}

	/**
	 * @param firstBitPos    First bit position (inclusive).
	 * @param lastBitPosExcl Last bit position (exclusive).
	 * @param bigEndian      True for bits to be added in big endian order (MSBit to
	 *                       LSBit) false for little endian order.
	 * @param padding        True if underscores must be added instead of
	 *                       out-of-range bits, false to just add characters
	 *                       corresponding to in-range bits.
	 * @return String representation of specified bits.
	 */
	public static String toStringBits(long bits, int firstBitPos, int lastBitPosExcl, boolean bigEndian, boolean padding) {
		checkBitPositionsLong(firstBitPos, lastBitPosExcl);
		final int bitSize = 64;
		final int bitSizeM1 = bitSize - 1;
		final int lastBitPos = lastBitPosExcl - 1;
		if (padding) {
			final int nbrOfChars = bitSize;
			final char[] chars = new char[nbrOfChars];
			int bitIndex = bitSizeM1;
			if (bigEndian) {
				final int firstBitIndex = bitSizeM1 - lastBitPos;
				final int lastBitIndex = bitSizeM1 - firstBitPos;
				while (bitIndex > lastBitIndex) {
					chars[bitSizeM1 - bitIndex] = '_';
					--bitIndex;
				}
				while (bitIndex >= firstBitIndex) {
					chars[bitSizeM1 - bitIndex] = (char) ('0' + ((bits >> bitIndex) & 1));
					--bitIndex;
				}
				while (bitIndex >= 0) {
					chars[bitSizeM1 - bitIndex] = '_';
					--bitIndex;
				}
			} else {
				while (bitIndex > lastBitPos) {
					chars[bitIndex] = '_';
					--bitIndex;
				}
				while (bitIndex >= firstBitPos) {
					chars[bitIndex] = (char) ('0' + ((bits >> bitIndex) & 1));
					--bitIndex;
				}
				while (bitIndex >= 0) {
					chars[bitIndex] = '_';
					--bitIndex;
				}
			}
			return new String(chars);
		} else {
			final int nbrOfChars = (lastBitPosExcl - firstBitPos);
			final char[] chars = new char[nbrOfChars];
			if (bigEndian) {
				final int firstBitIndex = bitSizeM1 - lastBitPos;
				final int lastBitIndex = bitSizeM1 - firstBitPos;
				int bitIndex = lastBitIndex;
				while (bitIndex >= firstBitIndex) {
					chars[lastBitIndex - bitIndex] = (char) ('0' + ((bits >> bitIndex) & 1));
					--bitIndex;
				}
			} else {
				int bitIndex = lastBitPos;
				while (bitIndex >= firstBitPos) {
					chars[bitIndex - firstBitPos] = (char) ('0' + ((bits >> bitIndex) & 1));
					--bitIndex;
				}
			}
			return new String(chars);
		}
	}

	/*
	 * toString (floating points)
	 * 
	 * toStringCSN(double) and toStringNoCSN(double) could be made faster, by using
	 * directly internals of Double.toString(double), but this would require
	 * copy-paste of much tricky code from JDK, and the overhead of our little
	 * rework is relatively negligible.
	 */

	/**
	 * @param value A double value.
	 * @return String representing the specified value, using "computerized
	 *         scientific notation", which Double.toString(double) uses for
	 *         non-infinite values, when |value| < 1e-3 or |value| >= 1e7.
	 */
	public static String toStringCSN(double value) {
		// Quick case (also to get rid of +-0.0,
		// for which Double.toString(double) doesn't use CSN).
		if (value == 0.0) {
			if (Double.doubleToRawLongBits(value) < 0) {
				return "-0.0E0";
			} else {
				return "0.0E0";
			}
		}

		final double abs = Math.abs(value);
		if ((abs >= NO_CSN_MIN_BOUND_INCL) && (abs < NO_CSN_MAX_BOUND_EXCL)) {
			final boolean neg = (value < 0.0);

			final String rawAbs = Double.toString(abs);
			if (abs >= 1.0) {
				/*
				 * 0123456 12.3456 ===> 1.23456E1 123.0 ===> 1.23E2
				 */
				final int dotIndex = rawAbs.indexOf((int) '.');
				final int powerOfTen = dotIndex - 1;
				final StringBuilder sb = new StringBuilder();
				if (neg) {
					sb.append('-');
				}
				// Adding unit-or-above digits, with dot after first one.
				sb.append(rawAbs.charAt(0));
				sb.append('.');
				sb.append(rawAbs, 1, dotIndex);
				if ((value != (int) value) || (abs < 10.0)) {
					// Adding below-unit digits (possibly just 0 if abs < 10.0,
					// to end up for example with "3.0E0" instead of "3.E0").
					sb.append(rawAbs, dotIndex + 1, rawAbs.length());
				}
				sb.append('E');
				sb.append(CHAR_BY_DIGIT[powerOfTen]);
				return sb.toString();
			} else {
				/*
				 * 012345678 0.0123456 ===> 1.23456E-2 0.01 ===> 1.0E-2
				 */
				int nonZeroIndex = 1;
				while (rawAbs.charAt(++nonZeroIndex) == '0') {
				}
				// Negative.
				final int powerOfTen = 1 - nonZeroIndex;
				final int nbrOfSignificantDigitsPastDot = (rawAbs.length() - (nonZeroIndex + 1));
				final StringBuilder sb = new StringBuilder();
				if (neg) {
					sb.append('-');
				}
				sb.append(rawAbs.charAt(nonZeroIndex));
				sb.append('.');
				if (nbrOfSignificantDigitsPastDot > 0) {
					// If bug 4428022 make rawAbs being something like "0.0010",
					// we add the last '0' here after the dot, which is fine.
					sb.append(rawAbs, nonZeroIndex + 1, rawAbs.length());
				} else {
					sb.append('0');
				}
				sb.append("E-");
				sb.append(CHAR_BY_DIGIT[-powerOfTen]);
				return sb.toString();
			}
		} else {
			return Double.toString(value);
		}
	}

	/**
	 * @param value A double value.
	 * @return String representing the specified value, not in "computerized
	 *         scientific notation", which Double.toString(double) uses for
	 *         non-infinite values, when |value| < 1e-3 or |value| >= 1e7.
	 */
	public static String toStringNoCSN(double value) {
		// Quick case.
		// Should also work with long instead of int,
		// but less obvious (due to roundings...),
		// and we just want to speed up the more common
		// case of "small" integer values.
		final int intValue = (int) value;
		if (value == intValue) {
			if (value == 0.0) {
				if (Double.doubleToRawLongBits(value) < 0) {
					return "-0.0";
				} else {
					return "0.0";
				}
			} else {
				return Integer.toString(intValue) + ".0";
			}
		}

		final String raw = Double.toString(value);
		final double abs = Math.abs(value);
		if (abs >= NO_CSN_MAX_BOUND_EXCL) {
			if (abs == Double.POSITIVE_INFINITY) {
				return raw;
			}
			/*
			 * 0123456789 1.234567E5 ===> 123456.7 1.23456E5 ===> 123456.0 (adding 0) 1.23E5
			 * ===> 123000.0 1.0E5 ===> 100000.0
			 */
			// "." close to start, so using indexOf.
			final int dotIndex = raw.indexOf((int) '.');
			// "E" close to end, so using lastIndexOf.
			final int eIndex = raw.lastIndexOf((int) 'E');
			final int powerOfTen = Integer.parseInt(raw.substring(eIndex + 1));
			final int nbrOfSignificantLoDigits = (eIndex - dotIndex - 1);
			final int nbrOfZerosToAddBeforeDot = (powerOfTen - nbrOfSignificantLoDigits);

			int start;
			int end;

			final StringBuilder sb = new StringBuilder();
			sb.append(raw, 0, dotIndex);
			if (nbrOfZerosToAddBeforeDot >= 0) {
				// Can copy all digits that were between '.' and 'E'.
				sb.append(raw, dotIndex + 1, eIndex);
				for (int i = 0; i < nbrOfZerosToAddBeforeDot; i++) {
					sb.append('0');
				}
				sb.append(".0");
			} else {
				start = dotIndex + 1;
				sb.append(raw, start, end = start + powerOfTen);

				sb.append('.');

				start = end;
				sb.append(raw, start, end = eIndex);
			}
			return sb.toString();
		} else if (abs < NO_CSN_MIN_BOUND_INCL) {
			// Not +-0.0 since already handled.
			/*
			 * 01234567 1.234E-4 ===> 0.0001234 1.0E-4 ===> 0.0001
			 */
			// "." close to start, so using indexOf.
			final int dotIndex = raw.indexOf((int) '.');
			// "E" close to end, so using lastIndexOf.
			final int eIndex = raw.lastIndexOf((int) 'E');
			// Negative.
			final int powerOfTen = Integer.parseInt(raw.substring(eIndex + 1));
			final int nbrOfZerosToAddAfterDot = (-powerOfTen - 1);

			final StringBuilder sb = new StringBuilder();
			if (value < 0.0) {
				sb.append("-0.");
			} else {
				sb.append("0.");
			}
			for (int i = 0; i < nbrOfZerosToAddAfterDot; i++) {
				sb.append('0');
			}
			// First raw digit.
			sb.append(raw, dotIndex - 1, dotIndex);
			if ((eIndex == dotIndex + 2) && (raw.charAt(dotIndex + 1) == '0')) {
				// Char past dot is alone and '0': no need to add it.
			} else {
				// Raw digits that were past dot.
				sb.append(raw, dotIndex + 1, eIndex);
			}
			return sb.toString();
		} else {
			// abs in [0.001,1e7[.
			if ((abs < 1.0) && (raw.charAt(raw.length() - 1) == '0')) {
				// Workaround for bug 4428022 (Double.toString(0.004) returns
				// "0.0040", same with 0.001 etc.).
				return raw.substring(0, raw.length() - 1);
			} else {
				return raw;
			}
		}
	}

	// --------------------------------------------------------------------------
	// PRIVATE METHODS
	// --------------------------------------------------------------------------

	private NumbersUtils() {
	}

	/*
	 * 
	 */

	/**
	 * Had such isInXXX methods, and corresponding checkXXX methods, but they seem
	 * actually slower in practice, so just keeping this code here in case some day
	 * it becomes faster than regular isInXXX.
	 * 
	 * Only works for non-empty ranges, i.e. such as min <= max. This treatment
	 * being designed for optimization, min <= max is not checked.
	 * 
	 * @return True if the specified value is in the specified range (inclusive),
	 *         false otherwise.
	 */
	private static boolean dontUseMe_isInNonEmptyRange_(int min, int max, int a) {
		// Using modulo arithmetic.
		return (Integer.MIN_VALUE + (a - min) <= Integer.MIN_VALUE + (max - min));
	}

	/*
	 * 
	 */

	private static int minSignedIntForBitSize_noCheck(int bitSize) {
		// i.e. (-1<<(bitSize-1))
		return (Integer.MIN_VALUE >> (32 - bitSize));
	}

	private static long minSignedLongForBitSize_noCheck(int bitSize) {
		// i.e. (-1L<<(bitSize-1))
		return (Long.MIN_VALUE >> (64 - bitSize));
	}

	private static int maxSignedIntForBitSize_noCheck(int bitSize) {
		// i.e. (1<<(bitSize-1))-1
		return (Integer.MAX_VALUE >> (32 - bitSize));
	}

	private static long maxSignedLongForBitSize_noCheck(int bitSize) {
		// i.e. (1L<<(bitSize-1))-1
		return (Long.MAX_VALUE >> (64 - bitSize));
	}

	/*
	 * 
	 */

	/**
	 * @throws IllegalArgumentException if the specified radix is out of range.
	 */
	private static int computeNbrOfDigits_negValue(int negValue, int radix) {
		checkRadix(radix);
		final int maxNbrOfDigits = MAX_NBR_OF_NEG_INT_DIGITS_BY_RADIX[radix];
		int p = radix;
		for (int i = 1; i < maxNbrOfDigits; i++) {
			if (negValue > -p) {
				return i;
			}
			p *= radix;
		}
		return maxNbrOfDigits;
	}

	/**
	 * @throws IllegalArgumentException if the specified radix is out of range.
	 */
	private static int computeNbrOfDigits_negValue(long negValue, int radix) {
		checkRadix(radix);
		final int maxNbrOfDigits = MAX_NBR_OF_NEG_LONG_DIGITS_BY_RADIX[radix];
		long p = radix;
		for (int i = 1; i < maxNbrOfDigits; i++) {
			if (negValue > -p) {
				return i;
			}
			p *= radix;
		}
		return maxNbrOfDigits;
	}

	/*
	 * 
	 */

	private static boolean checkBitPositions(int firstBitPos, int lastBitPosExcl, int bitSize) {
		if ((firstBitPos < 0) || (firstBitPos > lastBitPosExcl) || (lastBitPosExcl > bitSize)) {
			throw new IllegalArgumentException(
					"bit positions (first=" + firstBitPos + ",lastExcl=" + lastBitPosExcl + ") must verify 0 <= first <= lastExcl <= " + bitSize);
		}
		return true;
	}

	/**
	 * Common method for byte, short and int. Could be a bit faster to have specific
	 * methods for byte and short, but not much, and that would also make more messy
	 * (byte-)code.
	 * 
	 * @param bitSize Must be in [0,32].
	 */
	private static String toStringBits_0_32_bitPosAlreadyChecked(int bitSize, int bits, int firstBitPos, int lastBitPosExcl, boolean bigEndian,
			boolean padding) {
		final int bitSizeM1 = bitSize - 1;
		final int lastBitPos = lastBitPosExcl - 1;
		if (padding) {
			final int nbrOfChars = bitSize;
			final char[] chars = new char[nbrOfChars];
			int bitIndex = bitSizeM1;
			if (bigEndian) {
				final int firstBitIndex = bitSizeM1 - lastBitPos;
				final int lastBitIndex = bitSizeM1 - firstBitPos;
				while (bitIndex > lastBitIndex) {
					chars[bitSizeM1 - bitIndex] = '_';
					--bitIndex;
				}
				while (bitIndex >= firstBitIndex) {
					chars[bitSizeM1 - bitIndex] = (char) ('0' + ((bits >> bitIndex) & 1));
					--bitIndex;
				}
				while (bitIndex >= 0) {
					chars[bitSizeM1 - bitIndex] = '_';
					--bitIndex;
				}
			} else {
				while (bitIndex > lastBitPos) {
					chars[bitIndex] = '_';
					--bitIndex;
				}
				while (bitIndex >= firstBitPos) {
					chars[bitIndex] = (char) ('0' + ((bits >> bitIndex) & 1));
					--bitIndex;
				}
				while (bitIndex >= 0) {
					chars[bitIndex] = '_';
					--bitIndex;
				}
			}
			return new String(chars);
		} else {
			final int nbrOfChars = (lastBitPosExcl - firstBitPos);
			final char[] chars = new char[nbrOfChars];
			if (bigEndian) {
				final int firstBitIndex = bitSizeM1 - lastBitPos;
				final int lastBitIndex = bitSizeM1 - firstBitPos;
				int bitIndex = lastBitIndex;
				while (bitIndex >= firstBitIndex) {
					chars[lastBitIndex - bitIndex] = (char) ('0' + ((bits >> bitIndex) & 1));
					--bitIndex;
				}
			} else {
				int bitIndex = lastBitPos;
				while (bitIndex >= firstBitPos) {
					chars[bitIndex - firstBitPos] = (char) ('0' + ((bits >> bitIndex) & 1));
					--bitIndex;
				}
			}
			return new String(chars);
		}
	}
}
